package com.gopay.scheduler.job;

import com.gopay.common.asynexport.constants.AsynexportConstants;
import com.gopay.common.asynexport.service.AsynexportService;
import com.gopay.common.asynexport.vo.AsyncExportInfo;
import com.gopay.common.util.NamedThreadFactory;
import com.gopay.scheduler.GopayBaseJob;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by Think on 2017/8/30.
 */
@Service("asyncExportJob")
public class AsyncExportJob extends GopayBaseJob {

    private Logger logger = LoggerFactory.getLogger(AsyncExportJob.class);

    private static final int MAX_THREAD_COUNT = 3;

    private ExecutorService threadPool = Executors.newFixedThreadPool(MAX_THREAD_COUNT,new NamedThreadFactory("asyncexport"));

    @Resource(name = "asynexportService")
    private AsynexportService asynexportService;

    @Override
    protected void doJobInternal() {
        try {
            List<AsyncExportInfo> list = asynexportService.findWaitGenStatAsynExportList();
            if(list != null && !list.isEmpty()) {
                StopWatch sw = new StopWatch();
                sw.start();
                logger.info("异步导出文件,处理{}个文件",list.size());
                CountDownLatch latch = new CountDownLatch(list.size());
                for(int i = 0;i<list.size();i++) {
                    AsyncExportInfo vo = list.get(i);
                    AsyncExportTask task = new AsyncExportTask(vo,latch);
                    threadPool.execute(task);
                }
                //latch.await();
                // 同步锁存器等待所有线程执行完成
                if(!latch.await(20, TimeUnit.MINUTES)){
                    logger.error("同步锁存器等待超时了 latch.count=" + latch.getCount());
                    updateTimeoutRecordStatus(list);
                    threadPool.awaitTermination(10, TimeUnit.SECONDS);
                }

                sw.stop();
                long spendTime = sw.getTime();
                long sec = spendTime / 1000;
                long ns = spendTime % 1000;
                if (sec > 0) {
                    logger.info("异步导出文件生成完毕,耗时：{}秒{}毫秒", sec, ns);
                } else {
                    logger.info("异步导出文件生成完毕,耗时：{}毫秒",list.size(), ns);
                }
            }
        } catch (Exception e) {
            logger.error("异步导出文件生成出现异常！",e);
        }
    }

    private void updateTimeoutRecordStatus(List<AsyncExportInfo> list) {
        logger.error("处理同步锁存器超时，修改记录的状态。。。。start。。。。");
        try {
            for(AsyncExportInfo info : list) {
                if(!AsynexportConstants.DEAL_STATUS_SUCCESS.equals(info.getDealStatus())) {
                    if(info.getDealCount() >= AsynexportConstants.MAX_FAILED_COUNT) {
                        info.setDealStatus(AsynexportConstants.DEAL_STATUS_FAIL); //超过三次，更新为失败
                    } else {
                        info.setDealStatus(AsynexportConstants.DEAL_STATUS_WAIT); // 没有超过三次，更新为待生成
                    }
                    asynexportService.update(info);
                }
            }
        } catch (Exception e) {
            logger.error("处理同步锁存器超时，修改记录的状态。出现异常！",e);
        }
        logger.error("处理同步锁存器超时，修改记录的状态。。。。end。。。。");
    }



    class AsyncExportTask implements Runnable {

        private CountDownLatch latch;
        private AsyncExportInfo vo;

        public AsyncExportTask(AsyncExportInfo vo, CountDownLatch latch) {
            this.vo = vo;
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                // 1.锁定记录状态为生成中
                vo.setDealStatus(AsynexportConstants.DEAL_STATUS_DOING);
                vo.setDealCount(vo.getDealCount() + 1);
                vo.setLastDealTime(new Date());
                vo = asynexportService.update(vo);
                // 2.生成文件
                asynexportService.genFile(vo);
            } catch (Exception e) {
                logger.error("生成文件出错！",e);
                int dealCount = vo.getDealCount();
                if(dealCount >= AsynexportConstants.MAX_FAILED_COUNT) {
                    vo.setDealStatus(AsynexportConstants.DEAL_STATUS_FAIL); //超过三次，更新为失败
                } else {
                    vo.setDealStatus(AsynexportConstants.DEAL_STATUS_WAIT); // 没有超过三次，更新为待生成
                }
                vo.setLastDealTime(new Date());
                asynexportService.update(vo);
            } finally {
                latch.countDown();
            }
        }
    }
}
